2007年05月13日
川俣晶の縁側ソフトウェア技術雑記 total 10889 count

JavaScriptの匿名関数やC# 2.0の匿名メソッドがやたら便利な理由は何か?

Written By: 川俣 晶連絡先

 メソッドを変数や引数に入れる……というテクニックは、別に珍しいものではありません。

 アセンブラの時代には、ジャンプ先、コール先のアドレスを受け渡すのは珍しいことではないし、Cの関数ポインタも要するに同じことです。C# 1.xのdelegateも同じですね。

 しかし、それらは特別な場合にのみ使うものであって、それを多用したプログラミングは必ずしも楽ではありません。いろいろ面倒も抱え込むわけですね。

 それにも関わらず、JavaScriptの匿名関数やC# 2.0の匿名メソッドが湯水のごとく使いまくれるほど便利な理由は何か……。

 実際にコーディングして体感した理由はほとんど1つに絞られます。

 それは、「名前がない」ことではなく、「処理に必要なデータの受け渡しの面倒がない」ことです。

 たとえば、C# 1.xで書いているとき、delegate経由でメソッドAからメソッドBを呼び出す際、メソッドAが持つデータXをメソッドBが必要とした場合、かなり面倒なことになります。

 オーソドックスな解決方法と取ると仮定すると、まず、メソッドBはデータXを受け取る引数を追加しなければなりません。すると、delegateの定義と一致しなくなるので、delegateとの定義を直すか、修正した別の定義を追加しなければなりません。更に、メソッドBもデータXを渡すよう、修正しなければなりません。このような手間は渡すデータの量が多くなると非常に大きくなります。

 その結果、メソッドA、メソッドB、delegateの全ての変更が入ると同時に、個別のケースごとに専用のdelegateの定義がボコボコと増えていくことになります。これは、ソース管理という意味では鬱陶しい話です。どれがどこで使うdelegateか把握しきれなくなり、うかつな変更が悪い影響を及ぼすかもしれないからです。

 しかし、C# 2.0で匿名メソッドを使うとこのような問題が綺麗さっぱり無くなります。

 同じことを行う際、メソッドA、メソッドB、delegateの全てを修正する必要がありません。匿名メソッドであるメソッドBがメソッドAのスコープ内に書かれていれば、メソッドAが持つデータXはメソッドBからアクセス可能であるからです。

 必然的にdelegateの定義は滅多に増えません。それどころか、クラスライブラリが提供するMethodInvoker delegateだけで済んでしまうことも多いでしょう。

 というわけで、C# 1.xまでの時代と比較して、驚くほど少ない手間で「メソッドを変数や引数に入れる」プログラミングができてしまうわけです。

感想 §

 匿名メソッドを、名前がないことを最大の特徴とするメソッドと理解すると、存在意義を大きく見誤る可能性があると思いました。

 ってか、昔の自分はまさにそういう誤解をしていました。がっくし。